package com.example.invalidatetest;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;



import com.google.gson.Gson;

import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
import android.util.Log;
import android.view.DragEvent;
import android.view.GestureDetector;
import android.view.GestureDetector.OnDoubleTapListener;
import android.view.GestureDetector.OnGestureListener;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class InvalidateTests extends Activity implements OnTouchListener  {
	
	
	 //float touched_x, touched_y;
	 float translate_x, translate_y;
	 
	 
	 static PathGenerator uniGen = new PathGenerator();
	 
	 
		TextView tv_Status = null;
	    String serverIP = null;
	    EditText et_IP = null;
	    Button btn_connect = null;

	 
	    //vClass myView;
	    sView sView;
	    
	    int inputCount = 0;
	 
	    static Handler mHandler = null; //MAIN HANDLER
	    static Handler cHandler = null;
	    static Handler zHandler = null;
	    static LocationTracker locationTracker;
	    
	    networkConnection Network;
	    
	    
	    GestureDetector gestureDetector;
	    
	    Gson gson;
	    
	    
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_invalidate_tests);
		gson = new Gson();
		//myView = new vClass(this);
		sView = new sView(this);
		sView.setOnTouchListener(this);
		
		//setContentView(myView);
		
		setContentView(sView);
		
		//touched_x = 0;
		//touched_y = 0;
		
		translate_x = 0;
		translate_y = 0;
		
			
	
	    mHandler = new Handler() {
	        @Override
	        public void handleMessage(Message msg) 
	        {
	            String text = (String)msg.obj;
	            
	            tv_Status.setText("Connected to server");
	            
	            Log.v("NITESH",text); }
								    					};
								
															}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
	
		
		Log.d("MENU", item.getItemId() +"");
		
		//2131165189
		
		// 2131165190


		
		if(item.getItemId() == 2131165188){setContentView(sView);}
		if(item.getItemId() == 2131165187){setContentView(R.layout.network_layout);


		tv_Status = (TextView)findViewById(R.id.tv_status);
		et_IP = (EditText)findViewById(R.id.et_IP);
		btn_connect = (Button)findViewById(R.id.btn_connect);
		
		
		btn_connect.setOnClickListener(new View.OnClickListener() {
			
				@SuppressWarnings("unchecked")
				@Override
			public void onClick(View v) 
				{
				
				serverIP = et_IP.getText().toString();
				Network = new networkConnection();
				Network.execute();}}					);
		}
											

		
		return super.onOptionsItemSelected(item);
	}


	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.activity_invalidate_tests, menu);
		return true;
	}
	
	
	@SuppressLint("HandlerLeak")
	class sView extends SurfaceView {
		
		boolean offset = false;
		int newScrollX = 0;
		int newScrollY = 0;
		
		
		/* (non-Javadoc)
		 * @see android.view.View#onTouchEvent(android.view.MotionEvent)
		 */
		@Override
		public boolean onTouchEvent(MotionEvent event) {
			Log.d("NITESH", event.getX()+" X");
			Log.d("NITESH", event.getY()+" Y");

			   
			   	
			   return gestureDetector.onTouchEvent(event);
			 // return super.onTouchEvent(event);
		}
		

		ArrayList<PathCombinedColour> path_render_data = new ArrayList<PathCombinedColour>();
				
		//private Paint mPaint;
		private Paint mPaint = new Paint();
		
		
		//float ZoomConstant.scale_factor = 1f;
		
		
		public sView(Context c) {
			super(c);		
			setWillNotDraw(false);
			setFocusable(true);
						
			path_render_data.ensureCapacity(2000);
			
			gestureDetector = new GestureDetector(c, new GestureListener());
			
			locationTracker = new LocationTracker();
			
			
			
			cHandler = new Handler(){
				
		        @Override
		        public void handleMessage(Message msg) 
		        {
		            String text = (String)msg.obj;
		            
		            
		            if(text.equals("done")){
		            	Log.d("C HANDLER", "data set received");
		            	sView.invalidate();
		            }
		            
		            else{
		            
		            //int[][] from_server = gson.fromJson(text, int[][].class);
		            pathTagCombined Ptc = null;
		            
		            
		            try{
		            Ptc = gson.fromJson(text, pathTagCombined.class);}
		            catch(Exception e){e.printStackTrace();}
		            
		            //Log.v("Hashmap",Ptc.getTags().toString() + " tags"); 
		            
		            addShape(Ptc.getPath(),Ptc.getTags());
		            
		           //addShape(from_server);
		            
		            }
		            
		            
		        								}
									    					};
									    					
									    					
			zHandler = new Handler(){
				
				public void handleMessage(Message msg){
						ZoomConstant.scale_factor = ZoomConstant.scale_factor+0.1f;
						invalidate();
					
					
				}
				
				
			};
			
				
            mPaint = new Paint();
            mPaint.setAntiAlias(true);
            
            mPaint.setColor(Color.DKGRAY);
            mPaint.setStrokeWidth(20);
            mPaint.setTextSize(20);

            
		}
		
		public void addShape(int[][] coords, HashMap<String,String> tags){
			
			if(offset == false){
				
				OffsetConstant.offset_x = coords[0][0];
				OffsetConstant.offset_y = coords[0][1];
				offset = true;
				Log.d("OFFSET", "OFFSET");
				Log.d("OFFSET", OffsetConstant.offset_x+"x " + OffsetConstant.offset_x+" y");
				
			}
			
			
			PathCombinedColour ppc =  PathGenerator.PCCgenerator(coords);
					
			ppc.setTags(tags);
			
			Log.d("hashmap",ppc.getTags().size() +"");
			
			path_render_data.add(ppc);	
						
			//invalidate();
			
			
		}



		@SuppressLint("DrawAllocation")
		@Override
		protected void onDraw(Canvas canvas) {
			
			

			canvas.drawColor(Color.GRAY);
			
			Log.d("SCALE",ZoomConstant.scale_factor+"");
			
			canvas.scale(ZoomConstant.scale_factor,ZoomConstant.scale_factor);
			
			for(int i = 0; i< path_render_data.size(); i++){
				
				
			canvas.drawPath(path_render_data.get(i).getPath(), path_render_data.get(i).getPaint());
			
			//Log.d("path length", new PathMeasure(path_render_data.get(i).getPath(), false).getLength()+"");
			
			
			
			if(ZoomConstant.scale_factor > 1 && path_render_data.get(i).getTags().containsKey("name")){
				
				canvas.drawTextOnPath(path_render_data.get(i).getTags().get("name"), path_render_data.get(i).getPath(), 0, 10f, mPaint);
				
				/*
				
				String s = path_render_data.get(i).getTags().get("name");
				if(new PathMeasure(path_render_data.get(i).getPath(), false).getLength()/20 < s.length()){
					canvas.drawTextOnPath(path_render_data.get(i).getTags().get("name").substring(0, (int) new PathMeasure(path_render_data.get(i).getPath(), false).getLength()/20), path_render_data.get(i).getPath(), 0, 10f, mPaint);
				}
				
				*/
				
			}
			
			else if(
					
					(
					path_render_data.get(i).getTags().containsKey("rail") || 
					path_render_data.get(i).getTags().containsKey("railway") ||
					path_render_data.get(i).getTags().containsKey("highway") ||		
					path_render_data.get(i).getTags().containsKey("natural")		
							
							
							) 
					
					&& path_render_data.get(i).getTags().containsKey("name")
					){
				canvas.drawTextOnPath(path_render_data.get(i).getTags().get("name"), path_render_data.get(i).getPath(), 0, 10f, mPaint);
				
				/*
				
				String s = path_render_data.get(i).getTags().get("name");
				if(new PathMeasure(path_render_data.get(i).getPath(), false).getLength()/20 < s.length()){
					canvas.drawTextOnPath(path_render_data.get(i).getTags().get("name").substring(0, (int) new PathMeasure(path_render_data.get(i).getPath(), false).getLength()/20), path_render_data.get(i).getPath(), 0, 10f, mPaint);
				}
				
				*/
				
			}
			
				
				
				/**
			
			if(path_render_data.get(i).getTags().containsKey("name"))	{
				
				canvas.drawTextOnPath(path_render_data.get(i).getTags().get("name"), path_render_data.get(i).getPath(), 0, 0, mPaint);	
				
				}
			
			*/
				
				
				
			
			//Log.d("Hashmap", path_render_data.get(i).getTags().size() + " hashmap");
			//Log.d("Hashmap", path_render_data.get(i).getTags().get("name") + " hashmap name");
			
						
			//Log.d("Render", path_render_data.size() +"");
				}
			
			//Log.d("Render", canvas.isHardwareAccelerated() + " Acceleration" );

			
			Log.d("canvas bounds", canvas.getWidth() + " width " + canvas.getHeight() + " height");
			
		
			super.onDraw(canvas);
		}

		
//		public void testCases(){
//			
//			int[][] payload;
//			
//			String sample = "[[-13792,6717101],[-13759,6717134],[-13731,6717109],[-13758,6717083],[-13767,6717084],[-13784,6717067],[-13803,6717074],[-13792,6717101]]";
//		
//			payload = gson.fromJson(sample, int[][].class);
//			
//			OffsetConstant.offset_x = payload[0][0];
//			OffsetConstant.offset_y = payload[0][1];
//			
//			addShape(payload);
//			
//			
//			}

		}
	
	
	  class networkConnection extends AsyncTask<Object, Integer, Object>{
	    	
	    	public Socket socket = null;
	    	public  ObjectOutputStream objectOutputStream = null;
	    	public  ObjectInputStream objectInputStream = null;
	    	
	    	int port = 4444;	    	
	    	

		public networkConnection(){Log.d("NITESH", "new network 4 created");}
		
		
		public synchronized void sendToServer(String Request){

			try {
				
//				if(sView.path_render_data.size()>2000){
//				
//				sView.path_render_data.subList(2000, sView.path_render_data.size()-1);}
//				
				//sView.scrollTo(-200, -200);
				
				
				sView.scrollTo(0, 0);
				
				sView.path_render_data.clear();
				
				
				sView.offset = false;
				
				objectOutputStream.writeObject(Request);
				
			} 
			catch (IOException e) {e.printStackTrace();}
			
		}
	    		
	    		
		protected Object doInBackground(Object... params) {
			
			try {
						
				msg msgMessage = new msg("Android Device Connected");
				
				Message mMsg = new Message();
				mMsg.obj = "connected";
				
				mHandler.sendMessage(mMsg);
				
				DataRequest req = new DataRequest(-13905, 6716569,1);
				
				
				String json = gson.toJson(req);
				
				String msgSend = "android connected";
				
				if(socket == null) {
					socket = new Socket(serverIP, 4444);
					objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
					objectInputStream = new ObjectInputStream(socket.getInputStream());
					Log.v("NITESH", "connection established");}
					sView.scrollTo(-200, -200);
					objectOutputStream.writeObject(json);} 
			
			catch (UnknownHostException e) {e.printStackTrace();} 
			catch (IOException e) {e.printStackTrace();}
			
			
			while (objectInputStream != null) {
				
				Log.d("SERVER", "message received");
				
				String str = null;				
				msg ServerInput;
				
				
	        	
	        	try {    
	        		
	        		inputCount++;
	        		Log.d("SERVER", inputCount + " counter");
	        		
	        		
	        		str = (String) objectInputStream.readObject();	        		
	        		//ServerInput = gson.fromJson(str, msg.class);
	        		
	        		Message cMsg = new Message();
	        		cMsg.obj = str;
	        		
	        		Log.d("SERVER", "handler called");
	        		
	        		
	        		cHandler.sendMessage(cMsg);
	        		

	        		
	        		
	        	}
	        	
	        	catch(Exception e){}
	        	//END OF INPUT STREAM	
										}
			
			
/*			
			try {
				socket.close();
				objectOutputStream.close();
				objectInputStream.close();
				socket = null;
				objectInputStream = null;
				objectOutputStream = null;
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			*/
			
			// TODO Auto-generated method stub
			return null;		}


	    
	    }




	@Override
	public boolean onTouch(View v, MotionEvent event) {
		// TODO Auto-generated method stub
		return false;
	}

    class GestureListener extends GestureDetector.SimpleOnGestureListener {
    	
    	float touched_x, touched_y;
    	
    	
        @Override
        public boolean onDown(MotionEvent e) {
        	
            return true;
        }
        
        @Override
        public boolean onSingleTapConfirmed(MotionEvent event) {
        	Log.d("NITESH", event.getX()+" X");
			Log.d("NITESH", event.getY()+" Y");
			
			
			
			touched_x = event.getX();
			touched_y = event.getY();
						
			boolean hor = false;
			boolean vert = false;
						
			   if(touched_x >= 600){
				   sView.scrollBy(-100, 0);
				   locationTracker.movedLeft();
				  
			   }
			   
			   else if(touched_x <= 100){
				   sView.scrollBy(100, 0);
				   locationTracker.movedRight();
			   }
			   
			   else{
				   hor = true;
			   }
			   
			   
			   if(touched_y >= 900){
				   sView.scrollBy(0, -100);	
				   locationTracker.movedDown();

			   }
			   
			   else if(touched_y <= 100){
				   sView.scrollBy(0, 100);
				   locationTracker.movedUp();
			   }
			   
			   else{vert = true;}
			   
			   if(hor && vert){
	
				   Log.d("Scale", ZoomConstant.scale_factor+" click time");
				  
				   ZoomConstant.scale_factor = ZoomConstant.scale_factor +0.1f;
				   locationTracker.zoomChanged();
				   
				   sView.invalidate();
			   }
			   
            

            return true;
        }
        
        
        
        
        // event when double tap occurs
        @Override
        public boolean onDoubleTap(MotionEvent event) {
			Log.d("NITESH", event.getX()+" X");
			Log.d("NITESH", event.getY()+" Y");
			
			touched_x = event.getX();
			touched_y = event.getY();
			long currentClick = System.currentTimeMillis();
			
			boolean hor = false;
			boolean vert = false;
						
			   if(touched_x >= 600){
				   sView.scrollBy(-100, 0);
				   locationTracker.movedLeft();
				   				   
			   }
			   
			   else if(touched_x <= 100){
				   sView.scrollBy(100, 0);
				   locationTracker.movedRight();
			   }
			   
			   else{
				   hor = true;
			   }
			   
			   
			   if(touched_y >= 900){
				   sView.scrollBy(0, -100);
				   locationTracker.movedDown();

			   }
			   
			   else if(touched_y <= 100){
				   sView.scrollBy(0, 100);
				   locationTracker.movedUp();
			   }
			   
			   else{vert = true;}
			   
			   if(hor && vert){ /**IF CENTER OF DISPLAY*/
				   

				   Log.d("Scale", ZoomConstant.scale_factor+" click time");
				   				   
				   ZoomConstant.scale_factor = ZoomConstant.scale_factor -0.1f;
				   if(ZoomConstant.scale_factor < 0.1){ZoomConstant.scale_factor = 0.1f;}
				   locationTracker.zoomChanged();
				   
				   sView.invalidate();
			   }
			   
            

            return true;
        }
    }
	   
    class LocationTracker {
    	
    	int height_deviation = 0;
    	int width_deviation = 0;
    	
    	
    	int scaled_height_deviation = 0;
    	int scaled_width_deviation = 0;
    	
    	int zoom_level_request = 1;
    	
    	//SIZE OF CANVAS VISIBLE TO USE IS 720 WIDTH AND 1184 HEIGHT
    	
    	
    	int bounds = 2000; //NUMBER OF MERCATOR UNITS IN ALL DIRECTIONS FROM CENTRE
    	

    	public void movedLeft(){
    		width_deviation = width_deviation - 100;
    		deviationCheck();
    					}
    	
    	public void movedRight(){
    		width_deviation = width_deviation + 100;
    		deviationCheck();
    					}
    	
    	public void movedUp(){
    		height_deviation = height_deviation + 100;
    		deviationCheck();
    					}
    	
    	public void movedDown(){
    		height_deviation = height_deviation - 100;
    		deviationCheck();
    					}
    	
    	public void zoomChanged(){
    		
    		boolean zoomChanged = false;

    		if(ZoomConstant.scale_factor <= 0.3){
    			
    			if(zoom_level_request != 3){zoomChanged = true;}
    			
    			zoom_level_request = 3;
    			
    		}
    		else if(ZoomConstant.scale_factor <= 0.6){
    			
    			if(zoom_level_request != 2){zoomChanged = true;}
    			
    			zoom_level_request = 2;
    			
    		}
    		else{
    			if(zoom_level_request != 1){zoomChanged = true;}
    			
    			zoom_level_request = 1;
    			
    		}
    		
    		if(zoomChanged == true){boundsDeviated();}
    		else {deviationCheck();}

    	}
    	
    	public void deviationCheck(){
    		scaled_height_deviation = (int) (height_deviation * (1/ZoomConstant.scale_factor));
    		scaled_width_deviation = (int) (width_deviation * (1/ZoomConstant.scale_factor));
    		
    		if(Math.abs(scaled_height_deviation) >= bounds || Math.abs(scaled_width_deviation) >= bounds ){
    			Log.d("Location Tracker", "Bounds deviated, requesting new data");
    			boundsDeviated();
    		}
    		else{Log.d("Location Tracker", "Within range");}
    		
    		
    		
    	}
    	
    	public void boundsDeviated(){
    		    		
    		int x = OffsetConstant.offset_x + scaled_width_deviation;
    		int y = OffsetConstant.offset_y + scaled_height_deviation;
    		int zoom = zoom_level_request;
    		
    		height_deviation = 0;
    		width_deviation = 0;
    		
    		Network.sendToServer(gson.toJson(new DataRequest(x,y,zoom)));
    	}
    	
    	
    }

}
